{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dd7c9569",
   "metadata": {},
   "source": [
    "结果分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "7b6b4956",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入库\n",
    "import json\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from sklearn.metrics import roc_auc_score\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "983880ac",
   "metadata": {},
   "source": [
    "求threshold"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d62d435",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "threshold: 2.1499999999999972\n"
     ]
    }
   ],
   "source": [
    "processed_losses = []\n",
    "prev_value = 0\n",
    "window_size = 100 \n",
    "# 读取JSON文件\n",
    "with open('GAT_Attention_3_24_1.json', 'r') as f:#3代表三个GAT-Attention模块叠层，24代表历史步长为24，1代表预测步长为1\n",
    "    loaded_data = json.load(f)  # 自动解析为字典\n",
    "\n",
    "# 提取数组（确保键名一致）\n",
    "all_losses = loaded_data['all_losses']          # 损失值列表\n",
    "all_attack_labels = loaded_data['all_attack_labels']  # 标签列表\n",
    "all_attack_labels = all_attack_labels[window_size - 1:]\n",
    "\n",
    "threshold = 1.5  # 您可以根据需要调整阈值\n",
    "for loss, label in zip(all_losses, all_attack_labels):\n",
    "    if(loss<threshold):\n",
    "        temp_attack = 1\n",
    "    else:temp_attack = -1\n",
    "\n",
    "    if(temp_attack!=label):\n",
    "        if(temp_attack==1):\n",
    "            threshold = threshold - 0.01\n",
    "        else:threshold = threshold + 0.01\n",
    "print(\"threshold:\",threshold)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d66d8fd8",
   "metadata": {},
   "source": [
    "数据平滑"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "ed8f0c2f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loaded 17157 loss values\n",
      "Loaded 17157 labels\n"
     ]
    }
   ],
   "source": [
    "down_threshold = threshold\n",
    "processed_losses = []\n",
    "for i in range(window_size - 1, len(all_losses)):\n",
    "    window = all_losses[i - window_size + 1:i + 1]  # 取前 window_size 个元素\n",
    "    average = np.mean(window)\n",
    "    processed_losses.append(average)\n",
    "\n",
    "all_losses = processed_losses\n",
    "# 验证数据\n",
    "print(f\"Loaded {len(all_losses)} loss values\")       # 应输出类似：Loaded 5000 loss values\n",
    "print(f\"Loaded {len(all_attack_labels)} labels\")     # 应输出相同长度"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2909acc8",
   "metadata": {},
   "source": [
    "做图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "96960301",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建图形\n",
    "plt.figure(figsize=(15, 6))\n",
    "\n",
    "# 绘制阈值线\n",
    "# plt.axhline(y=threshold, color='blue', linestyle='--', label='Threshold')\n",
    "plt.axhline(y=down_threshold, color='blue', linestyle='--', label='Threshold')\n",
    "# plt.axhline(y=up_threshold, color='blue', linestyle='--', label='Threshold')\n",
    "# 初始化绘图参数\n",
    "prev_label = None\n",
    "start_idx = 1\n",
    "pre_color = \"green\"\n",
    "color = \"green\"\n",
    "# 遍历所有数据点\n",
    "for i in range(len(all_losses)):\n",
    "    current_label = all_attack_labels[i]\n",
    "    \n",
    "    # 当标签发生变化时绘制线段\n",
    "    if current_label != prev_label and prev_label is not None:\n",
    "        # 确定线段颜色：只要包含-1就使用红色\n",
    "        segment_labels = all_attack_labels[start_idx:i]\n",
    "        color = 'red' if -1 in segment_labels else 'green'\n",
    "        \n",
    "        # 绘制线段\n",
    "        if color==\"red\" and pre_color == \"green\":\n",
    "            plt.plot(range(start_idx-1, i+1), all_losses[start_idx-1:i+1],\n",
    "                    color=color, alpha=0.6,\n",
    "                    label='Attack' if start_idx == 0 else \"\")\n",
    "        elif color==\"green\" and pre_color == \"red\":\n",
    "            plt.plot(range(start_idx, i+1), all_losses[start_idx:i+1],\n",
    "                    color=color, alpha=0.6,\n",
    "                    label='Attack' if start_idx == 0 else \"\")\n",
    "        elif color==\"green\" and pre_color == \"green\":\n",
    "            plt.plot(range(start_idx, i), all_losses[start_idx:i],\n",
    "                    color=color, alpha=0.6,\n",
    "                    label='Attack' if start_idx == 0 else \"\")\n",
    "        elif color==\"red\" and pre_color == \"red\":\n",
    "            plt.plot(range(start_idx, i), all_losses[start_idx:i],\n",
    "                    color=color, alpha=0.6,\n",
    "                    label='Attack' if start_idx == 0 else \"\")\n",
    "        \n",
    "        # 更新起始点\n",
    "        start_idx = i\n",
    "    \n",
    "    pre_color = color\n",
    "    prev_label = current_label\n",
    "\n",
    "\n",
    "# 处理最后一段\n",
    "final_segment = all_attack_labels[start_idx:]\n",
    "color = 'red' if -1 in final_segment else 'green'\n",
    "plt.plot(range(start_idx, len(all_losses)), all_losses[start_idx:],\n",
    "        color=color, alpha=0.6)\n",
    "\n",
    "# 防止重复图例\n",
    "handles, labels = plt.gca().get_legend_handles_labels()\n",
    "by_label = dict(zip(labels, handles))\n",
    "\n",
    "# 添加图例和标签\n",
    "plt.xlabel('Sample Index')\n",
    "plt.ylabel('Error Score')\n",
    "plt.title('Error Score with Attack Labels (Red=Contains Attack, Green=Normal)')\n",
    "plt.legend(by_label.values(), by_label.keys())\n",
    "plt.grid(True)\n",
    "plt.tight_layout()\n",
    "plt.savefig('GAT_Attention_3_24_1.png', dpi=300)\n",
    "plt.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f234b91",
   "metadata": {},
   "source": [
    "计算评估指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "b4ace504",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "TP: 15346, TN: 428, FP: 582, FN: 801\n",
      "Precision: 0.9635\n",
      "Recall: 0.9504\n",
      "F1 Score: 0.9569\n",
      "AUC: 0.7740\n"
     ]
    }
   ],
   "source": [
    "predictions = []\n",
    "for loss in all_losses:\n",
    "    if loss < down_threshold:\n",
    "        predictions.append(1)  # 预测为正例\n",
    "    else:\n",
    "        predictions.append(-1)  # 预测为负例\n",
    "\n",
    "# 计算 TP, TN, FP, FN\n",
    "TP = TN = FP = FN = 0\n",
    "for pred, true in zip(predictions, all_attack_labels):\n",
    "    if pred == 1 and true == 1:\n",
    "        TP += 1\n",
    "    elif pred == -1 and true == -1:\n",
    "        TN += 1\n",
    "    elif pred == 1 and true == -1:\n",
    "        FP += 1\n",
    "    elif pred == -1 and true == 1:\n",
    "        FN += 1\n",
    "\n",
    "print(f\"TP: {TP}, TN: {TN}, FP: {FP}, FN: {FN}\")\n",
    "\n",
    "# 计算 Precision\n",
    "precision = TP / (TP + FP) if (TP + FP) > 0 else 0\n",
    "\n",
    "# 计算 Recall\n",
    "recall = TP / (TP + FN) if (TP + FN) > 0 else 0\n",
    "\n",
    "# 计算 F1 Score\n",
    "f1_score = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0\n",
    "\n",
    "print(f\"Precision: {precision:.4f}\")\n",
    "print(f\"Recall: {recall:.4f}\")\n",
    "print(f\"F1 Score: {f1_score:.4f}\")\n",
    "\n",
    "\n",
    "# 将预测标签转换为得分（假设 lower loss 表示 higher probability of positive）\n",
    "# 这里我们使用负的损失值作为得分\n",
    "scores = [-loss for loss in all_losses]\n",
    "\n",
    "# 计算 AUC\n",
    "auc = roc_auc_score(all_attack_labels, scores)\n",
    "print(f\"AUC: {auc:.4f}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
